// Hardware Buffer For OpenGL
// (c) jimon game studio

#ifndef JEH_CINDEXBUFFER_OPENGL
#define JEH_CINDEXBUFFER_OPENGL

#include "Config_Engine.h"
#include "jeDebug.h"
#include "jeOpenGLSystemHeader.h"
#include "je3dTypes.h"
#include "IHardwareBuffer.h"
#include "CRender_OpenGL_Extensions.h"

#ifdef JE_RENDER_OPENGL

#include "jeOpenGLWorkMode.h"

namespace je
{
	namespace video
	{
		//! Hardware Buffer For OpenGL
		class CHardwareBuffer_OpenGL:public je::video::IHardwareBuffer
		{
		protected:
			CRender_OpenGL_Extensions * Extensions;

			c8 * Array;
			Graphics3dDataType CurrentDataType;

			u1 Locked;
			core::BufferLockType LockType;

			u32 Size;
			u32 Position;

			GLenum BindTarget;
			GLuint VboId;

			u1 CurrentFromHWtoSWwhileLock;
			u1 CurrentFromSWtoHWwhileUnlock;

			OpenGLWorkMode CurrentWorkMode;
		public:
			//! Constructor
			CHardwareBuffer_OpenGL(CRender_OpenGL_Extensions * NewExtensions,GLenum Target,Graphics3dDataType DataType,OpenGLWorkMode WorkMode);

			//! Destructor
			~CHardwareBuffer_OpenGL();

			//! Lock Buffer
			void Lock(core::BufferLockType NewLockType);

			//! UnLock Buffer
			void UnLock();

			//! Return True if locked
			u1 IsLocked()
			{
				return Locked;
			}

			//! Read Data
			void Read(void * Pointer,u32 Bytes);

			//! Write Data
			void Write(const void * Pointer,u32 Bytes);

			//! Write Data From Other Buffer
			void WriteFrom(core::IBuffer * Buffer,u32 Bytes);

			//! Allocate Buffer for data
			void Allocate(u32 NewSize);

			//! DeAllocate Buffer
			void DeAllocate();

			//! Set Position
			void SetPosition(u32 NewPosition,u1 Relative = false)
			{
				if(Relative)
					Position += NewPosition;
				else
					Position = NewPosition;
			}

			//! Get Position
			u32 GetPosition()
			{
				return Position;
			}

			//! Get Size
			u32 GetSize()
			{
				return Size;
			}

			//! Get Size of one object
			u32 GetObjectSize()
			{
				return 1;
			}

			//! Merge Data
			void Merge(const void * Pointer,u32 ArraySize,u32 ObjectSize,u32 Stride);

			//! Get merged data blocks
			void UnMerge(void * Pointer,u32 ArraySize,u32 ObjectSize,u32 Stride,u32 Offset);

			//! Return true if hardware buffer enable
			u1 IsHardwareBufferEnable()
			{
				return CurrentWorkMode!=OWM_11;
			}

			//! Set auto update options
			void BufferAutoUpdateOptions(u1 FromHWtoSWwhileLock,u1 FromSWtoHWwhileUnlock)
			{
				CurrentFromHWtoSWwhileLock = FromHWtoSWwhileLock;
				CurrentFromSWtoHWwhileUnlock = FromSWtoHWwhileUnlock;
			}

			//! move data from software buffer to hardware buffer
			void MoveFromSoftwareToHardware();
	
			//! move data from hardware buffer to software buffer
			void MoveFromHardwareToSoftware();

			//! Get Data Type
			Graphics3dDataType GetDataType()
			{
				return CurrentDataType;
			}

			//! Copy Buffer to a new context or something else
			IHardwareBuffer * CopyAndRecreateBuffer();

			//! Get Ptr
			void * GetPtr()
			{
				return Array;
			}

			//! Return Vbo Id
			GLuint GetVboId()
			{
				return VboId;
			}

			//! Generate Buffers
			void GenerateBuffers();
		};
	}
}

#endif

#endif
